
sub eraseObjectFromScreen(iX as ubyte,fX as ubyte,iY as ubyte,fY as ubyte)
 dim xW as ubyte
 dim yW as ubyte
   for yW = iY to fY
         for xW =iX to fX
            imprimoCaracterMapa(xW, yW)
         next xW
        next yW
end sub
sub borraContenidoDialogoTexto(adr as uinteger)
    dim n as uinteger
    for n = adr to adr + 2048
            poke n , 0
    next n
end sub

sub DibujaDialogoTexto(y as ubyte)
    drawLine("A",y,1,30)   'draw horizontal line above    
    drawLine("B",y +7,1,30)   'draw horizontal line below
    drawLine("L",0,y+1,7)   'draw vertical line left
    drawLine("R",31,y+1,7)   'draw vertical line right
    print at y,0;chr(139) :print at y,31;chr(135)
    print at y+7,0;chr(142) :print at y+7,31;chr(141)
end sub

sub  saveUpperThirdOfScreen()
    SetSlot3(7)
     MemCopy(16384,57000,2048)
     MemCopy(22528,59048,256)
    SetSlot3(0)
end sub

sub  loadUpperThirdOfScreen()
    SetSlot3(7)
     MemCopy(57000,16384,2048)
     MemCopy(59048,22528,256)
    SetSlot3(0)
end sub

sub printTexto(xPixel as ubyte, yPixel as uinteger)
 
 printFzxSetMargin(0)
 printFzxAt(yPixel,xPixel)  
     
 SetSlot3(6)   
 printFzxStr(textMessage) 
 SetSlot3(0) 
   
      
 end sub
  
sub printTextoPlus(textAdr as uinteger,ByRef textLength as ubyte , xPixel as uinteger,yRow as ubyte, atribute as ubyte)
    dim yPixel as ubyte
    SetSlot3(6)
    yPixel= yRow * 8
    textLength = getTextLength(textAdr)
    WriteToTextVariable(textAdr,textLength)
    
     printTexto(10,yPixel)
    'change font color    
     cambiaAtributoLineaTexto(16384,yRow, atribute)
 
     limpiaVariableTextMessage(textLength)
       #IFDEF SONIDO_ACTIVADO
           ejecutaSonidoAy(procesa_una_nota) 
       #ENDIF

end sub
 /' *arguments(5)
   text address:         byRef uinteger its autoincrement after it call
   firstYpositionInCar: ubyte from 0 to 23
   qty:                  number off fragments to show
   textLength:           the length of the text been showned
   atribute :            the color of text to be showned.
   *Returns(2)
   text address:         point to the next text of the batch
   textlength:           returns the length of the text been showned
  '/
sub printBloqueTexto(byref textAdr as uinteger,altura as ubyte,qty as ubyte,byref textLength as ubyte, atribute)
  dim j as ubyte
  dim y as ubyte
  dim tercio as uinteger
  if textLength= 255 then
    y = 16
    tercio = 20480
  else
   tercio = 16384
  end if
  borraContenidoDialogoTexto(tercio)   
  'adr, segment,x, y,atribute,x px , y rows
 
  'textAdr = t_intro_wife
  'altura = 1
  for j =1 to qty
 
    printTextoPlus(textAdr,textLength,10,altura, atribute)
    
    altura = altura + 2
    textAdr = textAdr + textLength+1
  next j

 
  ink 7:DibujaDialogoTexto(y)
  refreshScreen()
  waitKeyPressAndDepress 
end sub
'rowNumber : 0 to 31
sub cambiaAtributoLineaTexto(screenAdr as uinteger,rowNumber as ubyte, atribute as ubyte)
dim atributeAdr as uinteger
dim rowAdr as uinteger
dim n as uinteger

atributeAdr = screenAdr + 6144 
rowAdr      = atributeAdr + cast(uinteger, rowNumber) * 32

for n = rowAdr to rowAdr +30
    poke n,atribute
next n
end sub

sub showInfoScreen()

dim tiempoActual as ulong

dim diferenciaTiempo as ulong
dim minutos as ulong
dim segundos as ulong
dim segundosTexto as string
dim minutosTexto as string
dim stringAImprimir as string
dim objectsToSort as ubyte
dim objectsToDispose as ubyte
dim n as ubyte
dim keyPressed as ubyte
switch2ShadowScreenSWR()
SetSlot3(7)
' Activamos el doble buffer
ActivarBuffer()

'MemCopy(16384,49152,6912)
BORDER 2: PAPER 0 
CLS


ink 1
drawLine("A",0,1,30)   'draw horizontal line above
drawLine("B",4,1,30)   'draw horizontalvline below
drawLine("L",9,1,3)   'draw vertical line left
drawLine("R",21,1,3)   'draw vertical line right
drawLine("L",17,6,5)   'draw vertical line left
drawLine("R",16,6,5)   'draw vertical line right
drawLine("B",10,1,30)   'draw horizontalvline below
ink 7
print at 1,13; "TIEMPO"
print at 6,1; "ITEMS A ORDENAR"
print at 6,18; "ITEMS A TIRAR"
SetSlot3(0)
objectsToSort    = getAmountofObjectsToSort()
objectsToDispose = getAmountofObjectsToDispose()
SetSlot3(7)

ink 4
DoubleSizeTexto (65,115,str(objectsToSort),2)
DoubleSizeTexto (185,115,str(objectsToDispose),2)

ink 2
DO 
    tiempoActual = t()
    diferenciaTiempo = TiempoFinalJuego - tiempoActual
    minutos  = diferenciaTiempo / (50*60)
    segundos = (diferenciaTiempo mod (50*60))/50
    
    
     segundosTexto = STR(segundos) 
     IF segundos < 10 then
       segundosTexto = "0"+ segundosTexto 
     end if
     
     minutosTexto = STR(minutos) 
     IF minutos < 10 then
       minutosTexto = "0"+ minutosTexto 
     end if
     

     stringAImprimir = minutosTexto+":"+segundosTexto
     
     keyPressed = DoubleSizeTexto(84,160,stringAImprimir,1)
     if keyPressed = 1 then
         SetSlot3(0)
         DesactivarBuffer()
         refreshScreen()
         
         exit do
     end if  
     
      GameStatus = checkForGameEnd(0)  
      if GameStatus then
        exit do
      end if
LOOP
border 2
end sub

sub drawLine(tipo as string,columnRow as ubyte,start as ubyte,qty as ubyte)
dim n as ubyte
dim tipoG as ubyte
if tipo = "A" then
    tipoG = 131
else if tipo = "B" then
    tipoG = 140
else if tipo = "L" then
    tipoG = 138
else if tipo = "R" then
    tipoG = 133
end if
if tipo = "A" or tipo = "B" then
    for n  =start to start+qty-1
        print at  columnRow,n;chr$(tipoG); 
    next n
else     
    for n = start to start+qty-1
        print at n,columnRow;chr$(tipoG);
    next n
end if
end sub

SUB refreshScreen()
        'pongo un waitretrace antes de cambiar slot porque lei que cambiar slot
        'en medio del frame puede ensuciar la imagen
        waitretrace
        SetSlot3(7)
        switch2NormalScreen()
        
        'waitretrace
        MemCopy(16384,49152,6912)
        #IFDEF SONIDO_ACTIVADO
            
            ejecutaSonidoAy(procesa_una_nota)
       
         #ENDIF
        'waitretrace
        switch2ShadowScreen()
        'pongo un waitretrace antes de cambiar slot porque lei que cambiar slot
        'en medio del frame puede ensuciar la imagen
        waitretrace
        SetSlot3(0)
END SUB

SUB switch2ShadowScreen()
    DIM bankM  AS UBYTE
    bankM = peek $5b5c
    bankM = bankM bOr %00001000
    POKE $5b5c,bankM
    'pongo waitretrace antes cambiar de pantalla porque lei que cambiar
    'de pantalla a mitad del frame puede dar suciedad en la pantalla
    waitretrace
    OUT $7ffd,bankM
END SUB

SUB switch2ShadowScreenSWR()
    DIM bankM  AS UBYTE
    bankM = peek $5b5c
    bankM = bankM bOr %00001000
    POKE $5b5c,bankM
    'pongo waitretrace antes cambiar de pantalla porque lei que cambiar
    'de pantalla a mitad del frame puede dar suciedad en la pantalla
    
    OUT $7ffd,bankM
END SUB


SUB switch2NormalScreen()
    DIM bankM  AS UBYTE
    bankM = peek $5b5c
    bankM = bankM bAnd %11110111
    POKE $5b5c,bankM
    'pongo waitretrace antes cambiar de pantalla porque lei que cambiar
    'de pantalla a mitad del frame puede dar suciedad en la pantalla
    waitretrace
    OUT $7ffd,bankM
END SUB

SUB switch2NormalScreenSWR()
    DIM bankM  AS UBYTE
    bankM = peek $5b5c
    bankM = bankM bAnd %11110111
    POKE $5b5c,bankM
    'pongo waitretrace antes cambiar de pantalla porque lei que cambiar
    'de pantalla a mitad del frame puede dar suciedad en la pantalla
   
    OUT $7ffd,bankM
END SUB


SUB ActivarBuffer()
    SetScreenBufferAddr(49152)
    SetAttrBufferAddr(55296)
END SUB 

SUB DesactivarBuffer() 
    SetScreenBufferAddr($4000) 
    SetAttrBufferAddr($5800)
END SUB



/'
 Construye una layer resumen especifica paara el Y del personaje.haciendo bOR(binary or) en todas las layers que cumplan el  requisito de que el Y inicial de la layer sea mayor que el Y del pie del personaje.
'/
 SUB buidUnionLayer() 
     DIM contador AS UINTEGER = 0
     DIM primeraCapa AS UBYTE = 0
     DIM yLayer AS UBYTE = 0
     DIM adrLayer AS UINTEGER
     DIM i AS UBYTE
     DIM atLeastOneLayer AS UBYTE = 0
     DIM n AS UBYTE
     'check every layer to see witch ones meet the criteria yLayer mayor que el pie del main character
     FOR n = 1 TO CantLayersActiveScreen
        adrLayer = AdrInicioCapasActiveScreen+contador
        yLayer = peek(adrLayer)
        
        IF yLayer > y+6 then
          atLeastOneLayer = 1
          
          
          
          
          IF primeraCapa > 0 then 
            FOR i = 0 TO 95
              POKE AdrUnionLayer+i,PEEK(AdrUnionLayer+i) bOR _ 
              PEEK(adrLayer+1+i)
            NEXT i
          ELSE
            MemCopy(AdrInicioCapasActiveScreen + contador + 1 _
            , AdrUnionLayer ,96)  
            primeraCapa = 1
          END IF
        END IF
        contador = contador +97
     NEXT n
     /'atLeastOneLayer se activa cuando al menos una capa entro en el criterio _
     y por lo tanto se actualizo la unionlayer. En caso que no se haya entrado _
     ninguna capa en el criterio , es necesario actualizar igual la unionLayer _
     porque sino queda con lo viejo cuando deberia quedar vacia. Ese es el motivo _
     del siguiente IF
     '/
     IF atLeastOneLayer = 0 then
        MemCopy(empty_layer,AdrUnionLayer,96)
     END IF
     
 END SUB

/' ARGUMENTOS
    adrHeader: direccion en memoria donde encontar al header del bloque
    startAdr: direccion donde comienzan los chunks ( pantallas, capas o limites)
    tipo : que se va a procesar del screen, contenido, capas o limites. 1 es el contenido del 
    screen  2 - son las capas del screen    3 - son los limites del screen
   OUTPUT
    retorno :
    Si tipo es 1: 
    la direccion de memoria donde esta los tiles del screen que corresponde con los xp e yp
    actuales.
    Si tipo es 2: 
    la direccion de memoria donde esta las layers del screen que corresponde con los xp e yp
    actuales
    Si tipo es 3:
    la direccion de memoria donde esta los limites del screen que corresponde con los xp e yp
    actuales
    
    Tambien retorna un segundo valor a traves de la variable tipo que es byref. Si el tipo que 
    ingreso en el input es 2 (layers), esta variable en su output retorna  la cantidad de capas
    que tiene el screen activo. En caso de que no hubiese ninguna layer para ese screen retorna 
    el valor -1 , en ese caso el retorno principal de la funcion es 0 porque no puedo encontrar
    ningun offset .
'/ 
FUNCTION findScreenBlock(adrHeader as UINTEGER,startAdr AS UINTEGER, BYREF tipo as BYTE) AS UINTEGER
        DIM contador AS UINTEGER
        DIM valorX , valorY as BYTE
        DIM offsetScreen AS UINTEGER
        DIM incremento AS UBYTE
        DIM offsetBloque AS UINTEGER
        
        'si esta procesando las tiles de una screen
        IF tipo = 1 then
            incremento = 4
        'si se esta procesando las capas de una screen
        ELSE IF tipo = 2 then 
            incremento = 5
        END IF
        'Ubico el contador que recorre el header de pantallas en el inicio del mismo
        contador = adrHeader
        'mientras no se termine el header continuo
        WHILE contador < startAdr
        'cargo valorX y valorY con el x, y de un block
            valorX = peek(contador)
            valorY = peek(contador +1)
            IF valorY <> yp then
                /'como yp contiene el y de la pantalla que queremos cargar, si valorY es diferente al 
                mismo significa que la pantalla que estamos navegando en el header no es la correcta, 
                asi que salto esa  parte del header y me ubico para leer la proxima'/
                contador = contador +incremento
                CONTINUE WHILE         
            ELSE if valorY = yp        
                IF valorX = xp         
                    offsetBloque = peek(contador +2)+peek(contador +3)*256
                    IF tipo = 2 then 
                        tipo = peek(contador +4)
                    END IF
                    RETURN offsetBloque
                    'EXIT WHILE
                END IF
            'creo que esta parte del codigo esta mal pero que no se nota porque hoy hay una sola
            'fila de screens , solo hay Y = 0  
            ELSE 
                EXIT WHILE
            END IF
            contador = contador +incremento 
        WEND 
        tipo = -1
        RETURN 0
END FUNCTION                       
 
              
              
 
/'
' primero waitretrace
1792, porque son 8 lineas x 224 tstates por linea  = 1792 es un caracter 
Por qué / 8?
Porque una iteración del FOR-NEXT en ZX BASIC compilado con optimización (-O2 por ejemplo) tarda alrededor de 8 t-states, aunque esto puede variar un poco según la implementación y optimización.
SUB espera_caracteres(cantCaracteres as ubyte)
    DIM t as uinteger
    DIM ciclos as uinteger
    ciclos = cantCaracteres * 1792 / 8   ' Aprox. 1 ciclo ZX BASIC = 8 t-states

    FOR t = 0 TO ciclos
        ' bucle vacío como delay
    NEXT t
END SUB
'/
SUB EsperaImpresion(caracterY as UBYTE)

  ASM  
   
     halt                 ; sincroniza al inicio del frame (línea 0)
    rlca                 ; A = A * 2
    rlca                 ; A = A * 4
    rlca                 ; A = A * 8 (8 líneas por carácter)
    ld b, a              ; B = número de líneas a esperar

esperar_loop:
    ; Este bucle toma 224 t-states ≈ 1 línea de video
    ld d, 64             ; 64 * (DEC + JP NZ) ≈ 224 t-states
delay_inner:
    dec d
    jp nz, delay_inner
    djnz esperar_loop
  END ASM
END SUB


SUB imprimoLineasSprite(cantLineas as UBYTE,offsetX as BYTE,offsetY as UBYTE, addrS as UINTEGER, addrA as UINTEGER)

  DIM yImpresion AS BYTE
  DIM xImpresion AS BYTE 
  DIM yMasOffset AS BYTE = y + offsetY
  DIM xMasOffset AS UBYTE = x + offsetX
  DIM diferencia AS UBYTE
  DIM longitudLineaSprite AS UBYTE
  DIM offsetYTotalLinea AS UBYTE
  DIM xViejo AS UBYTE
  DIM xViejoFinal AS UBYTE
  DIM xFinal AS UBYTE
  DIM  n AS UBYTE
  DIM r AS UBYTE
  FOR n  = 1 TO cantLineas
  longitudLineaSprite = coorSprites(n,2)
  offsetYTotalLinea = offsetY+n
    IF longitudLineaSprite > 0 then
      xImpresion  = xMasOffset + coorSprites(n,1)
      yImpresion  = yMasOffset +n -1
      xViejo        = xOld(offsetYTotalLinea)
      xViejoFinal   = xOldFinal(offsetYTotalLinea)
                      
      xFinal = xImpresion +longitudLineaSprite-1
      
      diferencia  = xImpresion - xViejo
     
     IF diferencia > 0 and diferencia <5  then        
       FOR r = 1 TO diferencia 
            imprimoCaracterMapa(xImpresion - r, yImpresion)
       NEXT r
      END IF
      /'
      De coorSprites saca la longitud de la linea anterior en forma acumulativa , para posicionar correctamente el 
      puntero en el caracter a imprimir entonces si quiero imprimir la linea 1 sera 0, la linea 2 sera la longitud 
      de la linea 1 *8 bytes, si quiere imprimir la linea 3 sera la longitud de la linea 1 mas la linea 2 y asi 
      
      '/ 
      imprimoLineaSprite(xImpresion,yImpresion,longitudLineaSprite, _
      addrS + cast(integer,coorSprites(n,3))*8, addrA+coorSprites(n,3))
     
     'IF borraDelanteDelSprite = 1 then
      
      
      diferencia = xViejoFinal - xFinal
       'el tema de la diferencia se puede achicar mas entiendo sin consecuencia. En los dos lados
       IF diferencia > 0 and diferencia <5  then        
            FOR r = 1 TO diferencia 
                imprimoCaracterMapa(xFinal + r, yImpresion)
            NEXT r
        END IF
         
        
      'END IF
       
      'borraDelanteDelSprite = 1
      xOld(offsetYTotalLinea) = xImpresion
      xOldFinal(offsetYTotalLinea) = xFinal
      
    END IF
  NEXT
  
END SUB   


SUB imprimoLineasSpriteGeneral(cantLineas as UBYTE,x as BYTE,y as UBYTE, addrS as UINTEGER, addrA as UINTEGER)

 
  DIM longitudLineaSprite AS UBYTE
  
  dim newSprite as uinteger
  dim newAtribute as uinteger
  DIM  n AS UBYTE
  DIM r AS UBYTE
  FOR n  = 1 TO cantLineas
  longitudLineaSprite = coorSprites(n,2)
    IF longitudLineaSprite > 0 then
      newSprite =addrS +  cast(integer,coorSprites(n,3))*8
      newAtribute = addrA+coorSprites(n,3)
      imprimoLineaSprite(x+coorSprites(n,1),y+n,longitudLineaSprite, _
      newSprite,newAtribute )
    END IF
    
  NEXT
  
END SUB   






SUB  imprimeSprite(x as UBYTE,y as UBYTE,largo as UBYTE, ancho as UBYTE,addr as INTEGER,addrA as INTEGER)  
      
      putChars(x ,y ,largo,ancho,addr)
      PaintData(x,y ,largo,ancho,addrA)
     'putChars(x ,y ,1,1,@burt_sup_wr1+0)
     'PaintData(x,y ,1,1,@burt_sup_wr1_Attr+0)   
END SUB

/'
INPUTS

* sentido: hacia donde esta tratando de moverse el personaje, posiblemente reemplazable
por variable global
OUTPUT
retorna booleano ,1 si se alcanzo el limite y sino no.
'/
FUNCTION alcanzoUnLimite() AS UBYTE 

/'
 El contenido de esta array representa limites verticales y horizontales, cada limite se
 define con cuatro valores: 
 * direccion(1-up,2-down,3-left,4-right). El limite solo se aplica si el personaje esta
 tratando de moverse hacia ese sentido.
 * eje limite( fila o columna donde esta el limite. Si direccion es 1 o 2, entonces 
 el eje sera fila, si la direcion es 3 o 4  entonces el eje sera columna
 * inicio: caracter donde comienza el limite
 * final: caracter donde termina el limite
 
 A su vez los dos primeros indices de la array indica
 primer indice: numero de pantalla
 segundo indice:  cantidad de limites en esa pantalla
 tercer indice: cantidad de elementos por limite
 el limite se computa utilizando el pie de berk para los horizontales y
 el final de la mano para los verticales 
'/ 

   
   DIM eje AS UBYTE   
   DIM inicio AS UBYTE   
   DIM final AS UBYTE
   DIM sentidoL AS UBYTE
   DIM offset AS BYTE
   DIM valorEje AS UBYTE
   dim incremento as ubyte
   
   sentidoL= peek(AdrScreenLimits + incremento) 
   'bucle que recorre todos los limites de la pantalla activa
   WHILE  NOT(sentidoL = 0)
     ' obtengo el sentido del limite que voy a procesar
      
    
     'si coinciden signica que dado la direccion en la que estoy caminando tengo
     'que procesar 
     IF sentidoL = mCO then
            'nro de fila o col.segun direccion
            valorEje   = peek(AdrScreenLimits +1 + incremento)  
            inicio     = peek(AdrScreenLimits +2 + incremento)  'inicio de limite
            final      = peek(AdrScreenLimits +3 + incremento) 'final de limite 
            IF mCO =1  then
                    offset = 0
                    /'si el pie del personaje coincide con el nro de fila + offset.
                    hay un igual porque piensa que el personaje va a estar totalmente del lado contrario al limite
                    entonces es cuando llegue a esa posicion cuando se activa el limite '/
                    IF y+6 = valorEje + offset then
                    'si no estoy por afuera del segmento retorno 1 porque hay colision
                        IF NOT((x+5 < inicio) or (x+1>final)) then
                            RETURN 1
                        END IF
                    END IF
            ELSE IF mCO = 2 then
                'si es hacia abajo agrego un offset de -1
                    offset = -1
                    IF y+6 = valorEje + offset then
                    'si no estoy por afuera del segmento retorno 1 porque hay colision
                        IF NOT((x+5 < inicio) or (x+1>final)) then
                            RETURN 1
                        END IF
                    END IF                   
            /'si el movimiento es para la izquierda o para la derecha valorEje es una col. Si el final x 
            del personaje coincide con la col.
            mCO =3 es izquierda '/
            ELSE IF (mCO =3) THEN 
                 IF x = valorEje or x = valorEje -1 or x = valorEje -2 then
                    IF NOT(y+6 < inicio or y+6 > final) then
                        RETURN 1
                   END IF
                 END IF
            'mCO =4 es a la derecha
            ELSE IF mCO=4 THEN
                IF x + 5 = valorEje or x + 5 = valorEje +1  or x + 5 = valorEje +2 then
                   IF NOT(y+6 < inicio or y+6 > final) then
                        RETURN 1
                   END IF
                END IF
            END IF
                
        END IF  
        incremento = incremento +4
        sentidoL= peek(AdrScreenLimits + incremento)
   END WHILE
   'si llego hasta aca sin volver antes , signica que no hay colision retorno 0
   RETURN 0
END FUNCTION


/'
  INPUTS
  xPos: x donde se empieza a imprimir la linea
  yPos: y de donde se empieza a imprimir la linea
  longitud: la cantidad de caracteres que tiene la linea a imprimir
  OUTPUT
  devuelve un entero:
  0 si todos los caracteres de la linea tienen mascara
  1 si ninguno de los caracteres de la linea tienen mascara
  2 si alguno de los caracteres de la linea tiene mascara
  
  Esta seteado para que la posicion de la pata del personaje sea menor o igual a 14. O sea que si es 14 o mas bajo hace el chequeo contra capa.  
'/
FUNCTION sinMascara(xPos as UBYTE, yPos as UBYTE,longitud as UBYTE) AS UBYTE
    DIM dato AS UBYTE  = 0
    DIM posicion AS INTEGER
    DIM n AS UBYTE
    ' si no hay layers en esta pantalla simplemente devuelvo 1 y listo
    IF CantLayersActiveScreen > 0 then
        FOR n = 0 TO longitud-1            
            posicion= obtenerPosicionEnMapa(xPos + n,yPos)           
            dato = dato + binariza(devuelveValorPosicionBitMap(posicion, AdrUnionLayer) )  
        NEXT n
    
        IF dato = longitud then
            RETURN 0
        ELSE IF dato = 0 then
            RETURN 1
        ELSE
            RETURN 2
        END IF
    ELSE 
        RETURN 1
    END  IF
END FUNCTION


/' 
INPUTS
* xPos coordenada x pantalla 0 a 31
* yPos coordenada y  0 a 23
OUTPUT
no hay retorno
ACCION
imprime en el x e Y suministrados el caracter que corresponde a esa posicion en el mapa
'/
SUB imprimoCaracterMapa(xPos as UBYTE, yPos as UBYTE)

 DIM posicionEnMapa AS UINTEGER
 DIM posicionEnPaleta AS UINTEGER
 
 
 'para que al reponer los tiles de paisaje solo los reponga si no hay obstaculo. Si hay obstaculo
 'significa que ya estaba bien de antes y no hay que reimprimir el tile. 
 if xPos <32 and xPos >-1 then
    if yPos >-1 and yPos < 24 then  
      drawTileInScreenFromXY(xPos,yPos)
    end if
 end if

 
END SUB

SUB imprimoLineaSprite(xLinea AS BYTE,yLinea as BYTE,longitud as BYTE,addressP as UINTEGER, addressA as UINTEGER)
DIM resultado AS UBYTE 
dim xPintado as ubyte
DIM difA AS UBYTE = 0
DIM n AS  UBYTE
  'Si resultado es 1 significa que hay que imprimir la linea completa(no hay nada en la capa que se sobreponga)
  
 
  /'
 comente este bloque como una prueba para ver la velocidad si siempre imprimo caracter a caracter y no por linea
  IF  resultado = 1 then
        'si la linea a imprimir supera el maximo horizontal de la pantalla se la achica al tamano donde no la supere
        'basicamente acorta el sprite cuando el personaje se sale de pantalla por la derecha
        IF (xLinea + longitud-1) > 31 then
       
            longitud = 31 - xLinea +1
            IF longitud < 0 then 
                longitud =0
            END IF   
        END IF
        'acorta  el sprite cuando el personaje de sale de pantalla por la izquierda
        IF xLinea < 0  then            
            longitud = longitud  + xLinea
            'difA queda cargado con la diferencia entre 0 y el valor y sirve para ajustar mas abajo el caracter al cual apuntar
             difA = abs (xLinea)
             xLinea= 0
        END IF
        'esto es necesario porque si de a que longitud es 0 o negativo y llamamos a putchar con un valor negativo o cero en 
        'longitud hace un desastre. Puede quedar en 0 con los recortes que hacemos en las secciones anteriores de esta subrutina
        IF longitud > 0 then 
            'Si el personaje estaba dentro de la pantalla , difA es 0 , si sale por izquierda sirve para ajustar la posicion 
            'donde esta el caracter que debemos imprimir
            putChars(xLinea,yLinea ,longitud,1,addressP+(difA*8))
           
            PaintData(xLinea,yLinea,longitud,1,addressA+difA)
        END IF
  'El resultado 2 significa que al menos 1 de los caracteres de la linea tiene algo superpuesto en la capa
  'verifica caracter a caracter para determinar en que caracter o caracteres hay superposicion y solo imprime aquellos donde no 
  'la hay.
  ELSE IF resultado = 2 then
  '/
  
        FOR n = 0 TO longitud -1
          xPintado = xLinea +n
          if xPintado <32 and xPintado > -1 then
           if yLinea > -1 and yLinea <24 then
            IF sinMascara(xPintado,yLinea,1) then          
                putChars(xPintado,yLinea ,1,1,addressP+8*n)
                PaintData(xPintado,yLinea,1,1,addressA+1*n)
            else
               if  mCO =1 then
                'esto logra sacar la basura que generaba el personaje cuando yendo para arriba chocaba parcialmente con objeto o paisaje
                imprimoCaracterMapa(xPintado,yLinea)
               end if
            END IF
          end if
         end if
        NEXT n     
  'END IF

END SUB



SUB imprimeCuadricula()
 DIM n AS UBYTE
 border 0: INK 7
    FOR n = 0 TO 23 
        PRINT AT n,0; n
    NEXT n 
    FOR n = 0 TO 9 
        PRINT AT 23,n; n
    NEXT n 
    FOR n = 0 TO 9 
        PRINT AT 23,n+10; n
    NEXT n 
    FOR n = 0 TO 9 
        PRINT AT 23,n+20; n
    NEXT n 
    FOR n = 0 TO 0 
        PRINT AT 23,n+30; n
    NEXT n
END SUB

SUB imprimoCaracteresMapa()
 DIM n AS UBYTE
 'hay que optimizarla entrando a imprimoCaracterMapa y modificandola
 FOR n = 1 TO 24
    IF abs(caracteresMapa(n,1)) < 35
      imprimoCaracterMapa(x+caracteresMapa(n,1), y +caracteresMapa(n,2))
    END IF
 'INK 7: PAPER 0
 'PRINT x+caracteresMapa(n,1); ",";y +caracteresMapa(n,2)
 NEXT n

END SUB


SUB drawScreenObjects()
  DIM contador AS UINTEGER
  DIM adrLineStart AS UINTEGER
  DIM valorX, valorY as BYTE
  'DIM offset AS UINTEGER
  DIM screenX AS UBYTE  
  DIM screenY AS UBYTE
  DIM linea AS UBYTE
  DIM inTheMap AS UBYTE 
  dim objectType as ubyte
  
  contador = OBJ_MAP_HEADER
  
  WHILE contador < OBJ_START
    objectType = peek(contador + 13)
      'cargo valorX y valorY con el x, y de un block
    inTheMap = peek(contador+1)
    IF inTheMap = 1  or inTheMap = 2 then  
      valorX = peek(contador+2)
      valorY = peek(contador +3)            
      IF (valorY = yp) AND (valorX = xp) THEN              
        screenX = PEEK(contador +4)  
        screenY = PEEK(contador +5)
        'offset = PEEK(UINTEGER,contador + 10)
        'draw object in the given coordinates, el 0 final es porque solo escribe en el mapa
        'de objetos pero no pinta los tiles(la rutina de impresion de pantalla lo hace despues
        if inTheMap = 1 then
         drawObject(contador, screenX,screenY)    
        else
           if objectType = 0
         drawObjectInFinalPosition(contador, screenX,screenY)
          end if
        end if
      END IF
    END IF      
    contador = contador + 15
  END WHILE
    
 END SUB   



SUB drawTileInScreenFromXY(column as ubyte , row as ubyte)
    
    DIM tilePosition as uinteger
    DIM valueTileObject AS UBYTE
    
    tilePosition = cast(uinteger,row) * 32 + cast(uinteger,column) +1
    valueTileObject = PEEK(AdrScreenObjectsTileMap+ tilePosition-1)
    
      IF valueTileObject > 0 then
        drawTileInScreenFromXYwithObjects(column,row)   
      ELSE        
        drawTileInScreenFromXYwithoutObjects(column,row)
      end if 
    
END SUB

sub  drawTileInScreenFromXYwithObjects(column as ubyte,row as ubyte)
     
    dim screenY as ubyte
    dim objectAdr as uinteger
    dim heightObject as ubyte
    dim  lastYObject as ubyte
    DIM tileObjectOffset AS UINTEGER
    DIM tilePosition as uinteger
    DIM valueTileObject AS UBYTE
    dim objectStatus as ubyte
    dim targetLayer as ubyte
    dim objectSupportLayer as ubyte
    
    tilePosition = cast(uinteger,row) * 32 + cast(uinteger,column) +1
    valueTileObject = PEEK(AdrScreenObjectsTileMap+ tilePosition-1)
     objectSupportLayer = peek(objectAdr +14)
     objectAdr        = findObjectAdrFromTileValue(valueTileObject)
     heightObject     = getObjectHeight(objectAdr)
     objectStatus     = peek (objectAdr + 1)
     screenY          = peek (objectAdr + 5)
     lastYObject      = screenY+heightObject-1   
     objectSupportLayer = peek(objectAdr +14)
     /'if object is in its final place then will only check obstruction in layers that
     are above the support structure in case there is a support structure for the object
     Else it will check obstruction en layers above the final y of the object.
     '/
     if objectStatus =2 then
        if objectSupportLayer <> 99 then
            targetLayer = objectSupportLayer
        else
            targetLayer = lastYObject+1
        end if
       
     else
      targetLayer = lastYObject+1
     end if
     
     if not getObstructionForAGivenPositionAndLayer (targetLayer,tilePosition)   then
            tileObjectOffset = (CAST(UINTEGER,valueTileObject)-1 )*8
            putChars(column,row ,1,1,paletaO_s + tileObjectOffset)
            PaintData(column,row,1,1,paletaO_a+ CAST(UINTEGER,valueTileObject) -1)
     else
        drawTileInScreenFromXYwithoutObjects(column,row)
     end if

end sub

sub drawTileInScreenFromXYwithoutObjects(column,row)
        
         DIM valueTileScreen AS UBYTE
         DIM tileScreenOffset AS UINTEGER
         DIM tilePosition as uinteger
         
         tilePosition = cast(uinteger,row) * 32 + cast(uinteger,column) +1

   /'
        busca en el mapa de 768 bytes que compone la pantalla, la posicion
        de paleta del byte a pintar
        '/
        valueTileScreen = peek(ADR_SCREEN_TILE_MAP+tilePosition-1) 
        
        /'  
        busca en la paleta la posicion que corresponde al dibujo que va en 
        el byte a pintar
        '/
        tileScreenOffset = (CAST(UINTEGER,valueTileScreen) -1)*8
        'se fija de que paleta tiene que buscar el tile
        IF devuelveValorPosicionBitMap(tilePosition, AdrPaletteExtension) > 0 then
         putChars(column, row ,1,1,paletaB_s + tileScreenOffset)
         PaintData(column,row ,1,1,paletaB_a+ CAST(UINTEGER,valueTileScreen)-1 )  
        ELSE
         IF valueTileScreen = 1 then
          PaintData(column,row ,1,1,paletaA_a + CAST(UINTEGER,valueTileScreen)-1 )
         ELSE
          putChars(column,row ,1,1,paletaA_s + tileScreenOffset)
          PaintData(column,row ,1,1,paletaA_a+ CAST(UINTEGER,valueTileScreen) -1)  
         END IF
        END IF
       

end sub


sub drawObject(objectAdr as uinteger,  screenX as ubyte,screenY as ubyte)  
  
  dim adrTargetLayer as uinteger
  dim heightObject as ubyte
  dim lastYObject as ubyte
  DIM lineQty  AS UBYTE
  DIM lineOffset AS UBYTE
  DIM lineFirstPosition AS UINTEGER
  DIM tileValue AS UINTEGER
  dim tilePosition as uinteger
  DIM n AS UBYTE
  DIM incrementoY AS UBYTE
  dim objectFirstPosition as uinteger  
  dim row as ubyte
  dim column as ubyte
  dim  adrLineStart as uinteger
  dim offset as uinteger
  

  offset  = peek(objectAdr+10)
  adrLineStart = OBJ_START +offset 
  
  objectFirstPosition = obtenerPosicionEnMapa(screenX,screenY)
  'busca la layer del objeto
  heightObject     = getObjectHeight(objectAdr)
  lastYObject      = screenY+heightObject-1
  adrTargetLayer   = searchLayerByY(lastYObject+1)
  'si no hay layer en el y del objeto la crea y si hay la modifica
  if adrTargetLayer = 0 then
    
    adrTargetLayer   = AdrInicioCapasActiveScreen+(cast(uinteger,CantLayersActiveScreen)*97)
    poke  adrTargetLayer, lastYObject+1
    MemCopy(empty_layer,adrTargetLayer +1,96)
    CantLayersActiveScreen =CantLayersActiveScreen+1
  end if

  DO   
    adrLineStart = adrLineStart + CAST(UINTEGER,lineQty)
    lineQty    = PEEK(adrLineStart)
    IF lineQty <> 99 then     
       lineOffset = PEEK(adrLineStart+1)
       FOR n = 0 TO lineQty - 1
         lineFirstPosition = objectFirstPosition +(32*incrementoY)
         tileValue =  peek(adrLineStart+2+ n)  
         tilePosition = lineFirstPosition + lineOffset + n
         
         POKE  AdrScreenObjectsTileMap + tilePosition -1 ,tileValue
         
         setValueInBitMap(tilePosition, adrTargetLayer +1, 1)
         'mirar , dibujando la pantalla estas lineas de texto no van(creo)
         
         
         'IF sinMascara(screenX+n,screenY,1) then
              row    = INT((tilePosition - 1) / 32)   ' división entera vía INT
              column = ((tilePosition - 1) MOD 32) 
              drawTileInScreenFromXYwithObjects(column,row)
              'drawTileInScreenFromXY(column,row)    'after paiting to the object tile map, now it paint the line in the real screen
         'end if
       NEXT n
       screenY = screenY +1
       incrementoY = incrementoY +1
       lineQty = lineQty+2
    ELSE
       EXIT DO
    END IF
  LOOP   

end sub


sub drawObjectInFinalPosition(objectAdr as uinteger,  xPosition as ubyte,yPosition as ubyte)  
  
  dim adrTargetLayer as uinteger
  dim objectHeight as ubyte
  dim objectLastY as ubyte
  DIM lineQty  AS UBYTE
  DIM lineOffset AS UBYTE
  DIM lineFirstPosition AS UINTEGER
  DIM tileValue AS UINTEGER
  dim tilePosition as uinteger
  DIM n AS UBYTE
  DIM incrementoY AS UBYTE
  dim objectFirstPosition as uinteger  
  dim row as ubyte
  dim column as ubyte
  dim adrLineStart as uinteger
  dim offset as uinteger
  dim objectSupportLayer as ubyte

  offset  = peek(objectAdr+10)
  adrLineStart = OBJ_START +offset 
  
  objectFirstPosition = obtenerPosicionEnMapa(xPosition,yPosition)
  'busca la layer del objeto
  objectHeight       = peek(objectAdr +12)
  objectSupportLayer = peek(objectAdr +14)
  objectLastY = yPosition + objectHeight-1
  
  'si no es 99 significa que el objeto no tiene base y hago lo habitual
  if objectSupportLayer = 99 then 
     adrTargetLayer   = searchLayerByY(objectLastY+1)
    'si no hay layer en el y del objeto la crea y si hay la modifica
     if adrTargetLayer = 0 then
        adrTargetLayer   = AdrInicioCapasActiveScreen+(cast(uinteger,CantLayersActiveScreen)*97)
        poke  adrTargetLayer, objectLastY+1
        MemCopy(empty_layer,adrTargetLayer +1,96)
        CantLayersActiveScreen =CantLayersActiveScreen+1
     end if
     'dibujo al mismo tiempo,la pantalla , el mapa de objetos y la layer.
     do   
      adrLineStart = adrLineStart + CAST(UINTEGER,lineQty)
      lineQty    = PEEK(adrLineStart)
      if lineQty <> 99 then     
        lineOffset = PEEK(adrLineStart+1)
        FOR n = 0 TO lineQty - 1
          lineFirstPosition = objectFirstPosition +(32*incrementoY)
          tileValue =  peek(adrLineStart+2+ n)  
          tilePosition = lineFirstPosition + lineOffset + n
          POKE  AdrScreenObjectsTileMap + tilePosition -1 ,tileValue
          setValueInBitMap(tilePosition, adrTargetLayer +1, 1)       
          row    = INT((tilePosition - 1) / 32)   ' división entera vía INT
          column = ((tilePosition - 1) MOD 32) 
          drawTileInScreenFromXYwithObjects(column,row)         
        NEXT n
        yPosition = yPosition +1
        incrementoY = incrementoY +1
        lineQty = lineQty+2
       else
          exit do
       end if
     loop
   else
     adrTargetLayer   = searchLayerByY(objectSupportLayer)
      'dibujo al mismo tiempo,la pantalla , el mapa de objetos y la layer.
     do   
      adrLineStart = adrLineStart + CAST(UINTEGER,lineQty)
      lineQty    = PEEK(adrLineStart)
      if lineQty <> 99 then     
        lineOffset = PEEK(adrLineStart+1)
        FOR n = 0 TO lineQty - 1
          lineFirstPosition = objectFirstPosition +(32*incrementoY)
          tileValue =  peek(adrLineStart+2+ n)  
          tilePosition = lineFirstPosition + lineOffset + n
          POKE  AdrScreenObjectsTileMap + tilePosition -1 ,tileValue
          setValueInBitMap(tilePosition, adrTargetLayer +1, 1)       
          row    = INT((tilePosition - 1) / 32)   ' división entera vía INT
          column = ((tilePosition - 1) MOD 32) 
          drawTileInScreenFromXYwithObjects(column,row)         
        NEXT n
        yPosition = yPosition +1
        incrementoY = incrementoY +1
        lineQty = lineQty+2
       else
          exit do
       end if
     loop
   
   end if
end sub


